package com.java.base.exercise.current;

import cn.hutool.core.util.ObjectUtil;

import java.util.Iterator;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;

/**
 * @Author RenPu
 * @Date 2022/2/15 14:23
 * @Version 1.0
 * @Description: 自定实现锁的核心思路
 **/
public class RenPuLock_version1 implements Lock {

    //1：需要有一个原子引用对象，监测对象锁标志的变化
    private volatile AtomicReference owen =new AtomicReference<>();


    //2：需要有一个队列容器，用于存储等待执行的线程
    private volatile LinkedBlockingDeque<Thread> waiterQueue=new LinkedBlockingDeque<>();


    /**
     * 如果变更成功，从队列尝试移除此线程
     * 如果变更失败，说明已经有线程更改过了，需要将线程放入队列容器，
     *为了防止反复放入队列容器，采用栈封闭声明标志位，线程放入队列容器更改标志位
     *将线程设置为挂起,后续收到通知唤醒等待的线程执行CAS方式获取锁
     */
    @Override
    public void lock() {

        //防止反复放入队列容器，采用栈封闭声明标志位，线程放入队列容器更改标志位
        boolean mark=true;
        //判断tryLock()尝试更改的结果
        while (!tryLock()){
            if(mark){
                //如果变更失败，说明已经有线程更改过了，需要将线程放入队列容器，
                waiterQueue.offer(Thread.currentThread());
                mark=false;
            }else {
               // 将线程设置为挂起,后续收到通知唤醒等待的线程执行CAS方式获取锁
                LockSupport.park();
            }
        }

        //防止首次线程获取锁，队列容器为空的时候
        if(ObjectUtil.isNotEmpty(waiterQueue)){
            //如果变更成功，从队列尝试移除此线程
            waiterQueue.remove(Thread.currentThread());
        }

    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }


    /**
     * 使用Unsafe中的CAS尝试变更原子引用对象的标识为当前线程
     * @return
     */
    @Override
    public boolean tryLock() {
        return owen.compareAndSet(null,Thread.currentThread());
    }

    @Override
    public boolean tryLock(long l, TimeUnit timeUnit) throws InterruptedException {
        return false;
    }


    /**
     * 1:通过CAS方式释放锁资源，将原子类引用对象设置为null
     * 2：从队列容器获取线程对象进行唤醒操作，去执行获取锁的机制
     */
    @Override
    public void unlock() {
        if(owen.compareAndSet(Thread.currentThread(),null)){
            Iterator<Thread> iterator = waiterQueue.iterator();
            while(iterator.hasNext()){
                Thread next = iterator.next();
                LockSupport.unpark(next);
            }
        }



    }

    @Override
    public Condition newCondition() {
        return null;
    }

    int i=0;
    public void add(){
        try {
            this.lock();
            i++;
        }finally {
            this.unlock();
        };

    }


    public static void main(String[] args) throws InterruptedException {

        RenPuLock_version1 renPuLock_version1 = new RenPuLock_version1();

        for (int i=0;i<4;i++){
            new Thread(()->{
                for (int j = 0; j <10000 ; j++) {
                    renPuLock_version1.add();
                }
            }).start();


        }

        Thread.sleep(2000L);
        System.out.println(renPuLock_version1.i);

    }
}
